#pragma once
#include <iostream>
#include <string>
#include <cstring>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

#define FIFO_NAME "fifo_plus"
#define PATH "."

#define ERROR_SHOW(msg)     \
	do                      \
	{                       \
		perror(msg);        \
		exit(EXIT_FAILURE); \
	} while (0)

class FifoPipe
{
public:
	FifoPipe(const std::string &name, const std::string &path) : _name(name), _path(path)
	{
		_fullname = _path + "/" + _name;
	}

	void CreatePipe()
	{
		umask(0);
		// 创建管道文件
		int n = mkfifo(FIFO_NAME, 0666);
		if (n < 0)
		{
			ERROR_SHOW("mkfifo error");
		}
		std::cout << "fifo create success, waiting for client start" << std::endl;
	}

	~FifoPipe()
	{
		// 删除管道文件
		int n = unlink(FIFO_NAME);
		if (n < 0)
		{
			ERROR_SHOW("unlink error");
		}
		else
		{
			std::cout << "unlink success" << std::endl;
		}
	}

private:
	std::string _name;
	std::string _path;
	std::string _fullname;
};

class FifoWork
{
public:
	FifoWork(const std::string &name, const std::string &path) : _name(name), _path(path)
	{
		_fullname = _path + "/" + _name;
	}

	void OpenForServer()
	{
		// 打开管道文件
		_fd = open(_fullname.c_str(), O_RDONLY);
		if (_fd < 0)
		{
			ERROR_SHOW("open error");
		}
		std::cout << "fifo open success, waiting for client to input" << std::endl;
	}

	void OpenForClient()
	{
		// 打开管道文件
		_fd = open(_fullname.c_str(), O_WRONLY);
		if (_fd < 0)
		{
			ERROR_SHOW("open error");
		}
		std::cout << "fifo open success, waiting for client to input" << std::endl;
	}

	void Write()
	{
		std::string str;
		while (true)
		{
			std::cout << "please input: ";
			std::getline(std::cin, str);
			int num = write(_fd, str.c_str(), str.size());
			if(str == "exit"){
				break;
			}
			if (num < 0)
			{
				ERROR_SHOW("write fail");
				break;
			}
			else if (num == 0)
			{
				std::cout << "write end" << std::endl;
				break;
			}
			else
			{
				std::cout << "write success" << std::endl;
			}
		}
	}

	void Read()
	{
		// 读取管道文件
		char buffer[1024];
		while (true)
		{
			int num = read(_fd, buffer, sizeof(buffer) - 1);
			if(strcmp(buffer, "exit") == 0){
				break;
			}
			if (num > 0)
			{
				buffer[num] = 0;
				std::cout << "client say: " << buffer << std::endl;
			}
			else if (num == 0)
			{
				std::cout << "client close" << std::endl;
				break;
			}
			else
			{
				ERROR_SHOW("read error");
			}
		}
	}

	void Close(){
		// 关闭管道文件
		close(_fd);
		std::cout << "close success" << std::endl;
	}

private:
	std::string _name;
	std::string _path;
	std::string _fullname;
	int _fd;
};